package com.vhall.component.service.lottery.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.vhall.component.dao.livecolumn.LiveColumnAttentionMapper;
import com.vhall.component.dao.lottery.*;
import com.vhall.component.dao.praise.RoomLikeMapper;
import com.vhall.component.entity.account.vo.AccountVO;
import com.vhall.component.entity.filter.vo.FilterWordsGetReqVO;
import com.vhall.component.entity.interactive.vo.QuestionPageRspVO;
import com.vhall.component.entity.livecolumn.LiveColumnAttention;
import com.vhall.component.entity.lottery.entity.LotteryAwardEntity;
import com.vhall.component.entity.lottery.entity.LotteryEntity;
import com.vhall.component.entity.lottery.entity.LotteryRecordEntity;
import com.vhall.component.entity.lottery.entity.LotteryUserEntity;
import com.vhall.component.entity.lottery.vo.*;
import com.vhall.component.entity.room.RoomLikesEntity;
import com.vhall.component.entity.room.dto.RoomExtendsDTO;
import com.vhall.component.entity.room.dto.RoomJoinsEntityDTO;
import com.vhall.component.entity.room.dto.RoomsEntityDTO;
import com.vhall.component.entity.room.vo.QueryRoomJoinsReqVO;
import com.vhall.component.entity.sign.vo.SignRecordPageVO;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.constant.RoomRoleNameCons;
import com.vhall.component.plugin.common.enums.LotteryTypeEnum;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.support.VssToken;
import com.vhall.component.plugin.common.support.VssTokenThreadLocal;
import com.vhall.component.plugin.common.utils.ArrayUtil;
import com.vhall.component.plugin.common.utils.JsonUtil;
import com.vhall.component.plugin.common.utils.RedisUtil;
import com.vhall.component.plugin.core.service.OssService;
import com.vhall.component.plugin.core.service.PaasService;
import com.vhall.component.service.account.AccountService;
import com.vhall.component.service.filter.FilterWordsConsoleService;
import com.vhall.component.service.interactive.QuestionService;
import com.vhall.component.service.livecolumn.LiveColumnService;
import com.vhall.component.service.lottery.AsyncTask;
import com.vhall.component.service.lottery.LotteryRecordRepository;
import com.vhall.component.service.lottery.LotteryRecordService;
import com.vhall.component.service.lottery.LotteryService;
import com.vhall.component.service.lottery.common.Consts;
import com.vhall.component.service.lottery.delay.LotteryDelayEvent;
import com.vhall.component.service.room.RoomInnerService;
import com.vhall.component.service.sign.service.SignInnerService;
import com.vhall.component.service.vote.delay.DelayEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 抽奖服务实现类
 *
 * @author song.dong
 */
@Slf4j
@Service
public class LotteryServiceImpl implements LotteryService {

    @Autowired
    private LotteryUserMapper lotteryUserMapper;


    @Autowired
    private PaasService paasService;
    @Autowired
    private LotteryMapper lotteryMapper;
    @Autowired
    private LotteryAwardMapper awardMapper;
    @Autowired
    private LotteryRecordMapper lotteryRecordMapper;

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisTemplate<String, String> stringRedisTemplate;


    @Autowired
    private OssService ossService;

    @Autowired
    private RedisUtil<LotteryUsersGetRspVO> redisGetHelper;
    @Autowired
    private DelayQueue<LotteryDelayEvent> lotteryDelayQueue;

    /**
     * 每个区间查询的数量
     */
    @Value("${vhall.lottery.perSectionNumber:1000}")
    private Integer perSectionNumber;
    @Value("${vhall.lottery.gif.url:https://wxtest.guosen.com.cn/gsoss/93c0f0022efa401e993190686b138abc.gif}")
    private String lotteryGifUrl;

    @Autowired
    private AsyncTask asyncTask;


    @Autowired
    private LotteryRecordService lotteryRecordService;

    @Autowired
    private RoomInnerService roomInnerService;

    @Autowired
    private QuestionService questionService;

    @Autowired
    private SignInnerService signInnerService;


    @Autowired
    private AccountService accountService;


    @Autowired
    private LotteryRecordRepository lotteryRecordRepository;
    @Autowired
    private RoomLikeMapper roomLikeMapper;
    @Autowired
    private LiveColumnAttentionMapper liveColumnAttentionMapper;
    @Autowired
    private LiveColumnService liveColumnService;
    @Autowired
    private FilterWordsConsoleService filterWordsConsoleService;

    /**
     * 从导入的用户进行 筛选
     *
     * @param roomId    room id
     * @param winnerOut 不允许重复中奖
     * @return count
     */
    public Integer getLotteryUserData(String roomId, Integer winnerOut) {
        QueryWrapper<LotteryUserEntity> where = new QueryWrapper<>();
        where.eq("room_id", roomId);
        if (winnerOut.equals(Consts.LOTTERY_EXCLUDE_WINNINGED)) {
            where.eq("is_winner", 0);
        }
        List<LotteryUserEntity> users = lotteryUserMapper.selectList(where);
        if (CollectionUtils.isEmpty(users)) {
            return 0;
        }
        List<Integer> userIds = users.stream().map(LotteryUserEntity::getId).collect(Collectors.toList());

        String key = Consts.KEY_LOTTERY_RANGE_IMPORT + roomId;
        redisTemplate.delete(key);
        // 添加缓存
        for (Integer id : userIds) {
            redisTemplate.opsForSet().add(key, id);
        }
        return userIds.size();
    }


    private String getAwardSnapShoot(Long awardId) {
        LotteryAwardEntity award = awardMapper.selectById(awardId);
        if (award == null) {
            return "";
        } else {
            return JSON.toJSONString(award);
        }
    }

    private AwardVO getAwardSnapShoot(String snapshoot) {
        if (StringUtils.isNotBlank(snapshoot)) {
            LotteryAwardEntity award = JSON.parseObject(snapshoot, LotteryAwardEntity.class);
            AwardVO awardVO = new AwardVO();
            BeanUtils.copyProperties(award, awardVO);
            return awardVO;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LotteryV4AddRspVO add(LotteryV4AddReqVO req) {
        VssToken vssToken = VssTokenThreadLocal.getToken();
        Integer thirdPartyUserId = vssToken.getThirdPartyUserId();

        if (req.getLotteryRule() == 2 && req.getLotteryType() == 3) {
            FilterWordsGetReqVO filterWordsGetReqVO = new FilterWordsGetReqVO();
            filterWordsGetReqVO.setRoomId(req.getRoomId());
            String filterWords = filterWordsConsoleService.getFilterWords(filterWordsGetReqVO);
            if (StrUtil.isNotEmpty(req.getLotteryJoinMark())) {
                if (StrUtil.containsIgnoreCase(filterWords, req.getLotteryJoinMark())) {
                    throw new BusinessException(60000, "评论内容包含敏感词", "");
                }
            }
        }

        RoomJoinsEntityDTO roomJoinsEntity = roomInnerService.getRoomJoinsByRoomIdAndThirdId(req.getRoomId(), thirdPartyUserId);
        if (roomJoinsEntity == null) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_USER);
        }
        try {
            String extendstr = req.getExtension();
            JSON.parseArray(extendstr, Extension.class);
        } catch (Exception e) {
            throw new BusinessException(BizErrorCode.COMP_LOTTERY_ERROR_EXTENDS);
        }

        //查询房间
        RoomsEntityDTO room = roomInnerService.getRoomInfo(req.getRoomId());
        if (null == room) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }

        String creatorNickname = StringUtils.isNotBlank(roomJoinsEntity.getNickname()) ? roomJoinsEntity.getNickname() : "";
        String creatorAvatar = StringUtils.isNotBlank(roomJoinsEntity.getAvatar()) ? roomJoinsEntity.getAvatar() : "";

        //加锁，避免重复提交
        Boolean isProcessing = stringRedisTemplate.opsForValue().setIfAbsent(RedisKey.LOTTERY_ADD_LOCK + req.getRoomId(),
                "1", req.getDuration() + 1, TimeUnit.SECONDS);
        if (isProcessing != null && !isProcessing) {
            throw new BusinessException(BizErrorCode.COMP_LOTTERY_REPEAT_COMMIT_ERROR);
        }

        // 判断当前是否有未结束的抽奖，如果有则结束再继续抽奖流程
        List<LotteryEntity> lotteryEntities = lotteryMapper.selectList(Wrappers.<LotteryEntity>lambdaQuery()
                .eq(LotteryEntity::getLotteryStatus, 0)
                .eq(LotteryEntity::getSourceId, req.getRoomId()));
        if (Objects.nonNull(lotteryEntities) && !lotteryEntities.isEmpty()) {
            //结束抽奖
            lotteryEntities.forEach(l -> {
                V4LotteryEndReqVO v4LotteryEndReqVO = new V4LotteryEndReqVO();
                v4LotteryEndReqVO.setLotteryId(l.getId().intValue());
                v4LotteryEndReqVO.setRoomId(l.getSourceId());
                end(v4LotteryEndReqVO);
            });
        }

        //第一步：创建抽奖
        LotteryEntity lottery = createLottery(req, vssToken.getAppId(), thirdPartyUserId, room, creatorNickname, creatorAvatar);
        // 满足条件抽奖
        if (req.getLotteryRule() == 2) {
            if (req.getLotteryType() == 3) {
                // 发表指定评论的用户
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("lotteryId", lottery.getId());
                jsonObject.put("comment", req.getLotteryJoinMark());
                stringRedisTemplate.opsForValue().set(RedisKey.KEY_LOTTERY_TYPE_COMMENT + room.getRoomId(), jsonObject.toJSONString(), 5, TimeUnit.MINUTES);
            }
        }
        //第二步：中奖流程，得到中奖的用户 核心逻辑
//        JSONArray winners = getWinners(req, room);
//        if (CollectionUtils.isNotEmpty(winners)) {
//            //更新抽奖的实际中奖人数
//            lottery.setActualLotteryNumber(winners.size());
//            lottery.setUpdatedAt(LocalDateTime.now());
//            lotteryMapper.updateById(lottery);
//            //第三步：记录中奖者
//            recordLotteryWinner(winners, lottery, req.getLotteryRule());
//            //第四步：调用PAAS发送消息
//            sendMessage(req, room, lottery);
//        }
        sendMessage(req, room, lottery);
        //存redis 供room取
        Map<String, Object> tollRecord = new HashMap<>(4);
        tollRecord.put("lottery_status", 1);
        tollRecord.put("lottery_id", lottery.getId());
        tollRecord.put("lottery_creator_id", vssToken.getThirdPartyUserId());
        redisTemplate.opsForHash().putAll(RedisKey.INTERACT_TOOL_RECORDS + room.getRoomId(), tollRecord);


        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        StringBuffer requestUrl = request.getRequestURL();

        log.info("添加抽奖到延时队列,房间:{},抽奖:{}", room.getIlId(), lottery.getId());
        LotteryDelayEvent event = new LotteryDelayEvent(lottery.getId(), lottery.getDuration(), room.getRoomId(), requestUrl.toString());
        event.setAccountId(thirdPartyUserId);
        event.setReqParam(req);
        lotteryDelayQueue.add(event);
        stringRedisTemplate.opsForList().rightPush(RedisKey.LOTTERY_DELAY_QUEUE, JSON.toJSONString(event));


        //第五步：构造发起抽奖返回数据
        return buildAddLotteryRsp(req, vssToken.getAppId(), lottery, null);
    }

    /**
     * 调用paas发送消息
     */
    private void sendMessage(LotteryV4AddReqVO req, RoomsEntityDTO room, LotteryEntity lottery) {
        VssToken vssToken = VssTokenThreadLocal.getToken();

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", "lottery_push_guoxin");
        jsonObject.put("room_id", room.getRoomId()); // 房间ID
        jsonObject.put("lottery_id", lottery.getId());  // 抽奖ID
        jsonObject.put("lottery_creator_id", vssToken.getThirdPartyUserId()); // 抽奖发起者ID
        jsonObject.put("lottery_creator_avatar", lottery.getCreatorAvatar());
        jsonObject.put("lottery_creator_nickname", lottery.getCreatorNickname());
        jsonObject.put("lottery_rule", lottery.getLotteryRule()); // 抽奖规则 1：随机抽奖  2：满足条件的抽奖
        jsonObject.put("lottery_type", lottery.getLotteryType()); // * 参与抽奖人员范围：1 参与点赞的用户  2 关注当前直播栏目的用户 3 发表指定评论的用户
        jsonObject.put("lottery_number", lottery.getActualLotteryNumber());
        jsonObject.put("lottery_status", lottery.getLotteryStatus());
        jsonObject.put("lottery_join_mark", req.getLotteryJoinMark()); // 参与抽奖的评论内容
        long remainTime = DateUtil.between(new Date(), lottery.getFinishTime(), DateUnit.SECOND, true);
        jsonObject.put("remain_time", remainTime); // 距离抽奖结束的剩余时间 单位/秒
        jsonObject.put("lottery_rule_text", req.getLotteryRuleText());
        jsonObject.put("lottery_gif_url", lotteryGifUrl);   //  抽奖中的动图

        paasService.sendMessage(room.getChannelId(), jsonObject.toJSONString());
        String extensionKey = RedisKey.LOTTERY_EXTENSION + room.getRoomId();
        if (StrUtil.isNotEmpty(req.getExtension())) {
            stringRedisTemplate.opsForValue().set(extensionKey, req.getExtension());
        }
    }

    /**
     * 构造发起抽奖返回数据
     */
    private LotteryV4AddRspVO buildAddLotteryRsp(LotteryV4AddReqVO req, String appId, LotteryEntity lottery, JSONArray winners) {
        LotteryV4AddRspVO lotteryV4AddRspVO = new LotteryV4AddRspVO();
        lotteryV4AddRspVO.setAppId(appId);
        lotteryV4AddRspVO.setId(lottery.getId());
        lotteryV4AddRspVO.setCreatorAvatar(lottery.getCreatorAvatar());
        lotteryV4AddRspVO.setCreatorId(lottery.getCreatorId());
        lotteryV4AddRspVO.setCreatorNickname(lottery.getCreatorNickname());
        lotteryV4AddRspVO.setLotteryNumber(lottery.getActualLotteryNumber());
        lotteryV4AddRspVO.setLotteryType(req.getLotteryType());
        lotteryV4AddRspVO.setSourceId(req.getRoomId());
        return lotteryV4AddRspVO;
    }

    /**
     * 记录中奖者
     */
    private void recordLotteryWinner(JSONArray winners, LotteryEntity lottery, int lotteryRule) {
        if (CollectionUtils.isEmpty(winners)) {
            return;
        }
        //批量保存抽奖记录
        batchSaveLotteryRecord(winners, lottery);

        List<Integer> userIdList = new ArrayList<>();
        winners.forEach(o -> {
            JSONObject jsonObject = (JSONObject) o;
            userIdList.add(jsonObject.getInteger("lottery_user_id"));
        });
        String key = 1 == lotteryRule ? RedisKey.LOTTERY_RANGE_ACCOUNTS + lottery.getSourceId() : RedisKey.LOTTERY_RANGE_IMPORT + lottery.getSourceId();

        if (2 == lotteryRule) {
            //自定义抽奖，更新lotteryUser的is_winner
            LambdaUpdateWrapper<LotteryUserEntity> wrapper = Wrappers.<LotteryUserEntity>lambdaUpdate()
                    .set(LotteryUserEntity::getIsWinner, 1)
                    .set(LotteryUserEntity::getUpdatedAt, LocalDateTime.now())
                    .eq(LotteryUserEntity::getAppId, lottery.getAppId())
                    .eq(LotteryUserEntity::getRoomId, lottery.getSourceId())
                    .in(LotteryUserEntity::getId, userIdList);
            lotteryUserMapper.update(null, wrapper);

        } else {

            RoomJoinsEntityDTO roomJoinsEntityDTO = new RoomJoinsEntityDTO();
            roomJoinsEntityDTO.setIsLotteryWinner(1);
            roomInnerService.updateLotteryWinner(roomJoinsEntityDTO, lottery.getSourceId(), userIdList);
        }

        //清空redis中的数据
        redisTemplate.delete(key);


    }

    private void upload(Long lotteryId, JSONArray winners, List<Integer> userIdList, int lotteryRule) {
        String fileName = "lottery_user.log";
        JSONObject content = new JSONObject();
        content.put("winner_user", winners);
        content.put("lotery_user_id", userIdList);
        content.put("lotery_rule", lotteryRule);
        content.put("lotery_data", "");
        String path = "upload/" + Consts.USER_NOTE_DIR + lotteryId;
        try {
            InputStream inputStream = new ByteArrayInputStream((content.toJSONString().getBytes()));
            String url = ossService.upload(inputStream, fileName, path);
            log.info("上传文件返回结果lotteryId:{},url{}", lotteryId, url);
        } catch (Exception e) {
            log.error("上传文件出错lotteryId:{},lotteryRule{}", lotteryId, lotteryRule, e);
        }
    }

    /**
     * 创建抽奖
     */
    private LotteryEntity createLottery(LotteryV4AddReqVO req, String appId, Integer thirdPartyUserId, RoomsEntityDTO room, String creatorNickname, String creatorAvatar) {
        LotteryEntity lottery = new LotteryEntity();
        LocalDateTime now = LocalDateTime.now();
        lottery.setBeginTime(new Date());
        lottery.setLotteryStatus(0);
        lottery.setAppId(appId);
        lottery.setSourceId(room.getRoomId());
        lottery.setCreatorId(thirdPartyUserId.toString());
        lottery.setCreatorNickname(creatorNickname);
        lottery.setCreatorAvatar(creatorAvatar);
        lottery.setLotteryType(req.getLotteryType());
        lottery.setLotteryRule(req.getLotteryRule());
        lottery.setLotteryNumber(req.getLotteryNumber());
        lottery.setExtension(req.getExtension());
        lottery.setTitle(req.getLotteryRuleText());
        lottery.setRepeatLottery(req.getWinnerOut());
        lottery.setDuration(req.getDuration());
        lottery.setFinishTime(DateUtil.offsetSecond(lottery.getBeginTime(), req.getDuration()));
        lottery.setCreatedAt(now);
        lottery.setUpdatedAt(now);
        lottery.setAwardSnapshoot(req.getAwardSnapshoot());
        lottery.setLotteryJoinMark(req.getLotteryJoinMark());
        lottery.setLotteryPrizeType(req.getLotteryPrizeType());
        lotteryMapper.insert(lottery);
        return lottery;
    }

    /**
     * 批量保存抽奖记录
     *
     * @param winners 中奖者
     */
    private void batchSaveLotteryRecord(JSONArray winners, LotteryEntity lottery) {
        List<LotteryRecordEntity> list = new ArrayList<>();
        for (Object o : winners) {
            JSONObject jsonObject = (JSONObject) o;
            LotteryRecordEntity lotteryRecordEntity = new LotteryRecordEntity();
            lotteryRecordEntity.setAppId(lottery.getAppId());
            lotteryRecordEntity.setLotteryId(lottery.getId());
            lotteryRecordEntity.setCreatorId(lottery.getCreatorId());
            lotteryRecordEntity.setCreatedAt(LocalDateTime.now());
            lotteryRecordEntity.setUpdatedAt(LocalDateTime.now());
            lotteryRecordEntity.setLotteryUserAvatar(jsonObject.getString("lottery_user_avatar"));
            lotteryRecordEntity.setLotteryUserId(jsonObject.getInteger("lottery_user_id").toString());
            lotteryRecordEntity.setLotteryUserNickname(jsonObject.getString("lottery_user_nickname"));

            lotteryRecordEntity.setLotteryUserName(jsonObject.getString("lottery_user_userName"));
            lotteryRecordEntity.setLotteryUserPhone(jsonObject.getString("lottery_user_phone"));
            lotteryRecordEntity.setLotteryUserRemark("");
            lotteryRecordEntity.setSourceId(lottery.getSourceId());
            lotteryRecordEntity.setPreset(jsonObject.getInteger("preset"));
            list.add(lotteryRecordEntity);
        }
        if (CollectionUtils.isNotEmpty(list)) {
            lotteryRecordRepository.saveBatch(list);

        }

    }

    /**
     * 中奖流程：得到中奖的用户
     */
    private JSONArray getWinners(LotteryV4AddReqVO req, RoomsEntityDTO room) {
        //中奖的人
        JSONArray winners = new JSONArray();
        //有预置中奖者
        //对于 自定义抽奖  这里的id  是手机号
        // 对于  不是自定义抽奖  这里的id  是 用户 账号id:accountId
        if (StringUtils.isNotBlank(req.getLotteryUserIds())) {
            String[] lotteryUserIdsArr = req.getLotteryUserIds().split(",");
            //预置的中奖用户ID数量大于中奖的人数
//            if (lotteryUserIdsArr.length > req.getLotteryNumber()) {
//                throw new BusinessException(BizErrorCode.COMP_LOTTERY_OVER_NUMBER_ERROR);
//            }
            //去重
            Stream<String> stream = Arrays.stream(lotteryUserIdsArr);
            List<String> list = stream.distinct().collect(Collectors.toList());


            // 获取预置中奖用户信息
            JSONArray preWinners = new JSONArray();
            Integer lotteryRule = req.getLotteryRule();
            if (lotteryRule == 1) {
                //指定列表通过 accountId查询， 转换成数字
                List<Integer> integerList = new ArrayList<>();
                try {
                    CollectionUtils.collect(list, o -> Integer.valueOf(String.valueOf(o)), integerList);
                } catch (NumberFormatException e) {
                    throw new BusinessException(BizErrorCode.BIZ_INVALID_PARAM);
                }
                // 指定列表查询
                QueryRoomJoinsReqVO reqVO = new QueryRoomJoinsReqVO();
                reqVO.setRoomId(req.getRoomId());
                StringJoiner joiner = new StringJoiner(",");
                for (Integer pageDatum : integerList) {
                    joiner.add(pageDatum.toString());
                }
                reqVO.setAccountIds(joiner.toString());
                List<RoomJoinsEntityDTO> rjedtos = roomInnerService.getRoomJoinsList(reqVO);
                for (RoomJoinsEntityDTO roomJoinsEntityDTO : rjedtos) {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("lottery_user_id", roomJoinsEntityDTO.getAccountId());
                    jsonObject.put("preset", 1);
                    jsonObject.put("lottery_user_phone", roomJoinsEntityDTO.getUsername());
                    jsonObject.put("lottery_user_userName", roomJoinsEntityDTO.getUsername());
                    jsonObject.put("lottery_user_nickname", roomJoinsEntityDTO.getNickname());
                    jsonObject.put("lottery_user_avatar", roomJoinsEntityDTO.getAvatar());
                    preWinners.add(jsonObject);
                }
                winners.addAll(preWinners);
            } else {
                // 自定义列表查询，通过 userName查询
                List<LotteryUserEntity> lotteryUserEntities = lotteryUserMapper.selectList(
                        Wrappers.<LotteryUserEntity>lambdaQuery().eq(LotteryUserEntity::getRoomId, req.getRoomId()).in(CollectionUtils.isNotEmpty(list), LotteryUserEntity::getUsername, list));
                for (LotteryUserEntity lotteryUserEntity : lotteryUserEntities) {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("lottery_user_id", lotteryUserEntity.getId());
                    jsonObject.put("lottery_user_nickname", lotteryUserEntity.getNickname());
                    jsonObject.put("lottery_user_userName", lotteryUserEntity.getUsername());
                    jsonObject.put("lottery_user_phone", lotteryUserEntity.getUsername());
                    jsonObject.put("preset", 1);
                    preWinners.add(jsonObject);
                }
                winners.addAll(preWinners);
            }
            //获取对应的抽奖池key
            String key = req.getLotteryRule() == 2 ?
                    RedisKey.LOTTERY_RANGE_IMPORT + req.getRoomId() :
                    RedisKey.LOTTERY_RANGE_ACCOUNTS + req.getRoomId();
            int lotteryNumber = req.getLotteryNumber();
            for (String userId : list) {
                //这个代码的意思是 移除   中奖id  但是 对于自定义的话 移除不了，因为自定义的 redis 里面是id  但是 这个list里面
                //  是 用户手机号
                // 对于  非自定义 可以正常移除用户id
                redisTemplate.opsForSet().remove(key, userId);
                lotteryNumber--;
            }

            //剩余名额走无预置中奖逻辑
            //  lotteryNumber  代表  减去了  预置的抽奖人
            //  还剩下的需要抽奖的人数  剩余人数 大于0的时候 代表 还需要在 redis里面在抽
            if (lotteryNumber > 0) {
                JSONArray randomWinners = randomWinners(req, lotteryNumber, room, preWinners);
                winners.addAll(randomWinners);
            }
        } else {
            //无预置中奖者
            JSONArray randomWinners = randomWinners(req, req.getLotteryNumber(), room, null);
            winners.addAll(randomWinners);
        }
        return winners;
    }


    /**
     * @param req               发起抽奖请求VO
     * @param needLotteryNumber 需要抽取的人数
     * @param room              房间
     * @param preWinners        预置的中奖人（满足抽奖条件人数>=5000的时候需要用到）
     * @return 随机中奖的人
     */
    private JSONArray randomWinners(LotteryV4AddReqVO req, Integer needLotteryNumber, RoomsEntityDTO room, JSONArray preWinners) {
        //随机抽取中奖者
        JSONArray randomWinners = new JSONArray();
        Integer lotteryRule = req.getLotteryRule();
        String roomId = req.getRoomId();
        String key = 1 == lotteryRule ? RedisKey.LOTTERY_RANGE_ACCOUNTS + roomId : RedisKey.LOTTERY_RANGE_IMPORT + roomId;
        Set<Integer> winnerIdList = new HashSet<>();

        //已中奖的人数
        if (CollectionUtils.isNotEmpty(preWinners)) {
            preWinners.forEach(object -> {
                JSONObject jsonObject = (JSONObject) object;
                winnerIdList.add(jsonObject.getInteger("lottery_user_id"));
            });
        }

        RoomExtendsDTO roomExtendsDTO = roomInnerService.getRoomExtendsByRoomId(room.getRoomId());
        if (roomExtendsDTO == null) {
            throw new BusinessException("查询不到开播时间");
        }
        long satisfyLotteryPersons = redisTemplate.opsForSet().size(key);
        // TODO 记得放开
//        if (needLotteryNumber > satisfyLotteryPersons) {
//            throw new BusinessException(BizErrorCode.COMP_LOTTERY_NUMBERS_OVER_RANGE);
//        }
        //移除 预置中奖人的id
        if (CollectionUtils.isNotEmpty(winnerIdList)) {
            redisTemplate.opsForSet().remove(key, winnerIdList.toArray());
        }
        while (needLotteryNumber > 0) {
            //  redis里面 随机 抽取 id
            List<Integer> userIdList = redisTemplate.opsForSet().randomMembers(key, needLotteryNumber);
            Set<Integer> userIds = new HashSet<>(userIdList);
            if (CollectionUtils.isEmpty(userIds)) {
                break;
            }
            //移除中将人id
            redisTemplate.opsForSet().remove(key, userIds.toArray());
            if (CollectionUtils.isNotEmpty(userIds)) {
                if (2 == lotteryRule) {
                    //自定义抽奖
                    List<LotteryUserEntity> lotteryUserEntities = lotteryUserMapper.selectList(
                            Wrappers.<LotteryUserEntity>lambdaQuery()
                                    .eq(LotteryUserEntity::getRoomId, roomId)
                                    .in(LotteryUserEntity::getId, userIds));
                    for (LotteryUserEntity lotteryUserEntity : lotteryUserEntities) {
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("lottery_user_id", lotteryUserEntity.getId());
                        jsonObject.put("lottery_user_nickname", lotteryUserEntity.getNickname());
                        jsonObject.put("lottery_user_userName", lotteryUserEntity.getNickname());
                        jsonObject.put("lottery_user_phone", lotteryUserEntity.getUsername());
                        jsonObject.put("preset", 0);
                        randomWinners.add(jsonObject);
                        needLotteryNumber--;
                    }
                } else {
                    QueryRoomJoinsReqVO reqVO = new QueryRoomJoinsReqVO();
                    reqVO.setRoomId(roomId);
                    StringJoiner joiner = new StringJoiner(",");
                    for (Integer pageDatum : userIds) {
                        joiner.add(pageDatum.toString());
                    }
                    reqVO.setAccountIds(joiner.toString());
                    List<RoomJoinsEntityDTO> srjedtos = roomInnerService.getRoomJoinsList(reqVO);
                    for (RoomJoinsEntityDTO roomJoinsEntity : srjedtos) {
                        if (req.getWinnerOut() == 1 && roomJoinsEntity.getIsLotteryWinner() == 1) {
                            redisTemplate.opsForSet().remove(key, roomJoinsEntity.getAccountId());
                            continue;
                        }
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("lottery_user_id", roomJoinsEntity.getAccountId());
                        jsonObject.put("lottery_user_nickname", roomJoinsEntity.getNickname());
                        jsonObject.put("lottery_user_avatar", roomJoinsEntity.getAvatar());
                        jsonObject.put("lottery_user_userName", roomJoinsEntity.getUsername());
                        jsonObject.put("lottery_user_phone", roomJoinsEntity.getUsername());
                        jsonObject.put("preset", 0);
                        needLotteryNumber--;
                        redisTemplate.opsForSet().remove(key, roomJoinsEntity.getAccountId());
                        randomWinners.add(jsonObject);
                    }
                }
            }
        }
        return randomWinners;
    }

    /**
     * 计算总数
     */
    private Integer countTotalPersons(Integer lotteryType, RoomsEntityDTO room) {
        int total = 0;
        if (lotteryType == 1 || lotteryType == 4 || lotteryType == 5) {
            //全体参会用户，全体观众，已登录观众，查PAAS在线人数
            total = paasService.getUserOnlineCount(room.getChannelId()).intValue();
        } else if (lotteryType == 2 || lotteryType == 6) {
            //2参与问卷的参会者 6为参与问卷的观众
            String startTime = room.getStartTime().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
            total = questionService.queryAllPartakeAccountsCount(room.getRoomId(), startTime);
        } else if (lotteryType == 3 || lotteryType == 7) {
            //3参与签到的参会者 7参与签到的观众
            String startTime = room.getStartTime().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
            total = signInnerService.countPartakeTotalAfterLiveStart(room.getRoomId(), startTime);
        }
        return total;
    }


    /**
     * 随机区间获取符合抽奖类型的业务端的用户
     */
    private List<Integer> getSectionDataFromBusiness(List<Integer> sectionArray, Integer lotteryType
            , int needLotteryNumber, String startLiveDateTime, LotteryV4AddReqVO req) {
        //返回数据
        List<Integer> returnList = new ArrayList<>();
        //要获取的区间的个数
        int intervalCount = (int) Math.ceil(needLotteryNumber * 1.0 / perSectionNumber) + 1;
        //和业务数据区交集
        if (lotteryType == 2 || lotteryType == 6) {
            //2参与问卷的参会者  6 //参与问卷的观众
            List<Integer> sectionRandomList = ArrayUtil.randomGetElement(sectionArray, intervalCount, true);
            returnList = getQuestData(sectionRandomList, startLiveDateTime, req.getRoomId());
        } else if (lotteryType == 3 || lotteryType == 7) {
            //3 参与签到的参会者
            //7 参与签到的观众
            List<Integer> sectionRandomList = ArrayUtil.randomGetElement(sectionArray, intervalCount, true);
            returnList = getSignData(sectionRandomList, startLiveDateTime, req.getRoomId());
        }
        return returnList;
    }

    /**
     * 随机区间取paas的在线用户
     */
    private List<Integer> getSectionDataFromPaas(List<Integer> sectionArray, String channelId, int needLotteryNumber) {
        //返回数据
        List<Integer> returnList = new ArrayList<>();
        //要获取的区间的个数
        int intervalCount = (int) Math.ceil(needLotteryNumber * 1.0 / perSectionNumber) + 1;
        //随机获取N个区间
        List<Integer> sectionRandomList = ArrayUtil.randomGetElement(sectionArray, intervalCount, true);
        log.info("随机区间列表（paas消息服务）：" + sectionRandomList.toString());

        List<Future<List<Integer>>> onlineUserFutureList = new ArrayList<>();
        for (Integer sectionValue : sectionRandomList) {
            Future<List<Integer>> onlineUserFuture = asyncTask.getOnlineUsersFromPaas(sectionValue, 1000, channelId);
            onlineUserFutureList.add(onlineUserFuture);
        }
        // 接收数据 (3)
        for (Future<List<Integer>> onlineUserFuture : onlineUserFutureList) {
            try {
                List<Integer> onlineUidList = onlineUserFuture.get();
                returnList.addAll(onlineUidList);
            } catch (InterruptedException e) {
                log.error(e.getMessage());
                Thread.currentThread().interrupt();
            } catch (ExecutionException e) {
                log.error(e.getMessage());
            }
        }
        return returnList;

    }

    private List<Integer> getQuestData(List<Integer> sectionRandomList, String startLiveDateTime, String roomId) {
        List<Integer> returnList = new ArrayList<>();
        List<Future<QuestionPageRspVO<Integer>>> signFutureList = new ArrayList<>();
        for (Integer sectionValue : sectionRandomList) {
            Future<QuestionPageRspVO<Integer>> signFuture = asyncTask.getQuestUsersAfterStartLive(sectionValue, perSectionNumber, roomId, startLiveDateTime);
            signFutureList.add(signFuture);
        }
        for (Future<QuestionPageRspVO<Integer>> future : signFutureList) {
            QuestionPageRspVO<Integer> rspVO;
            try {
                rspVO = future.get();
                List<Integer> firstSignData = rspVO.getData();
                returnList.addAll(firstSignData);
            } catch (InterruptedException e) {
                log.error("抽奖add获取Quest数据出错", e);
                Thread.currentThread().interrupt();
            } catch (ExecutionException e) {
                log.error("抽奖add获取Quest数据出错", e);
            }
        }
        return returnList;
    }


    private List<Integer> getSignData(List<Integer> sectionRandomList, String startLiveDateTime, String roomId) {
        List<Integer> returnList = new ArrayList<>();
        List<Future<SignRecordPageVO<Integer>>> signFutureList = new ArrayList<>();
        for (Integer sectionValue : sectionRandomList) {
            Future<SignRecordPageVO<Integer>> signFuture = asyncTask.getSignUsersAfterStartLive(sectionValue, perSectionNumber, roomId, startLiveDateTime);
            signFutureList.add(signFuture);
        }
        for (Future<SignRecordPageVO<Integer>> future : signFutureList) {
            SignRecordPageVO<Integer> rspVO;
            try {
                rspVO = future.get();
                List<Integer> firstSignData = rspVO.getData();
                returnList.addAll(firstSignData);
            } catch (InterruptedException e) {
                log.error("抽奖add获取签到数据出错", e);
                Thread.currentThread().interrupt();
            } catch (ExecutionException e) {
                log.error("抽奖add获取签到数据出错", e);
            }
        }
        return returnList;
    }


    /**
     * * 参与抽奖人员范围：
     * * 1 全体参会用户
     * * 2 参与问卷的参会者
     * * 3 参与签到的参会者
     * * 4.全体观众
     * * 5.已登录观众
     * * 6.参与问卷的观众
     * * 7.参与签到的观众
     *
     * @param lotteryType
     * @param accountIdList
     * @param winnerOut
     * @return
     */
    private List<Integer> filter(String channelId, String roomId, int lotteryType, List<Integer> accountIdList, int winnerOut) {
        if (CollectionUtils.isEmpty(accountIdList)) {
            return Collections.emptyList();
        }
        QueryRoomJoinsReqVO reqVO = new QueryRoomJoinsReqVO();
        //过滤参会者
        reqVO.setRoomId(roomId);
        if (Stream.of(1, 2, 3).anyMatch(x -> x == lotteryType)) {
            reqVO.setRoleNameOperate(SqlKeyword.GT.getSqlSegment());
            reqVO.setRoleName(RoomRoleNameCons.ROLE_OWNER);
        } else if (Stream.of(4, 5, 6, 7).anyMatch(x -> x == lotteryType)) {
            reqVO.setRoleNameOperate(SqlKeyword.EQ.getSqlSegment());
            reqVO.setRoleName(RoomRoleNameCons.ROLE_AUDIENCE);
        }
        if (winnerOut == 1) {
            reqVO.setIsLotteryWinner(0);
        }
        reqVO.setRoomId(roomId);
        StringJoiner joiner = new StringJoiner(",");
        for (Integer pageDatum : accountIdList) {
            joiner.add(pageDatum.toString());
        }
        reqVO.setAccountIds(joiner.toString());
        List<RoomJoinsEntityDTO> rjedtos = roomInnerService.getRoomJoinsList(reqVO);
        List<Integer> ids = rjedtos.stream().map(RoomJoinsEntityDTO::getAccountId).collect(Collectors.toList());
        //过滤已登陆
        if (lotteryType == 5 && CollectionUtils.isNotEmpty(ids)) {
            ids = accountService.filterAccountType(ids);
        }
        //过滤在线状态
        if (Stream.of(2, 3, 6, 7).anyMatch(x -> x == lotteryType) && CollectionUtils.isNotEmpty(ids)) {
            Map<String, Object> onlineQuesResult = checkUserStatus(channelId, ids);
            ids = onlineQuesResult.entrySet().stream()
                    .filter(entity -> (Integer) entity.getValue() == 1)
                    .map(entity -> Integer.valueOf(entity.getKey())).collect(Collectors.toList());
        }
        return ids;
    }

    private Map<String, Object> checkUserStatus(String channelId, List<Integer> ids) {
        List<List<Integer>> lists = Lists.partition(ids, 200);
        Map<String, Object> result = new HashMap<>(16);
        List<Future<Map<String, Object>>> onlineUserFutureList = new ArrayList<>();
        for (List<Integer> sectionValue : lists) {
            Future<Map<String, Object>> onlineUserFuture = asyncTask.checkUserStatus(channelId, sectionValue);
            onlineUserFutureList.add(onlineUserFuture);
        }
        // 接收数据 (3)
        for (Future<Map<String, Object>> onlineUserFuture : onlineUserFutureList) {
            try {
                Map<String, Object> onlineUidMap = onlineUserFuture.get();
                result.putAll(onlineUidMap);
            } catch (InterruptedException e) {
                log.error(e.getMessage());
                Thread.currentThread().interrupt();
            } catch (ExecutionException e) {
                log.error(e.getMessage());
            }
        }
        return result;
    }


    private Integer getLeftSeconds(Date beginTime) {
        if (beginTime == null || System.currentTimeMillis() >= beginTime.getTime()) {
            return 0;
        }
        return Math.toIntExact((beginTime.getTime() - System.currentTimeMillis()) / 1000);
    }


    @Override
    public String publish(V4LotteryPublishReqVO req) {
        Validate.notNull(req);
        Integer lotteryId = req.getLotteryId();
        String roomeId = req.getRoomId();
        String jsonPath = stringRedisTemplate.opsForValue().get(Consts.LOTTERY_WINNERS_JSON_URL + lotteryId);
        if (Objects.isNull(jsonPath)) {
            throw new BusinessException(BizErrorCode.COMP_LOTTERY_NOT_FOUND);
        }
        RoomsEntityDTO room = roomInnerService.getRoomInfo(req.getRoomId());
        if (null == room) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }

        Map<String, Object> json = new HashMap<>(4);
        json.put("type", "lottery_result_notice_guoxin");
        json.put("room_id", roomeId);
        json.put("lottery_id", lotteryId);
        json.put("lottery_winners_url", jsonPath);
        paasService.sendMessage(room.getChannelId(), JsonUtil.toJsonString(json));

        redisTemplate.opsForHash().delete(RedisKey.INTERACT_TOOL_RECORDS + room.getRoomId(), "lottery_status", "lottery_id");
        return jsonPath;
    }

    @Override
    public LotteryInfoVO info(V4LotteryPublishReqVO reqVo) {
        LotteryInfoVO vo = new LotteryInfoVO();
        vo.setIsJoin(0);
        vo.setLotteryGifUrl(lotteryGifUrl);
        LotteryEntity lotteryEntity = lotteryMapper.selectById(reqVo.getLotteryId());
        if (lotteryEntity == null) {
            throw new BusinessException(BizErrorCode.EMPTY_DATA);
        }
        vo.setLotteryId(Math.toIntExact(lotteryEntity.getId()));
        vo.setTitle(lotteryEntity.getTitle());
        vo.setLotteryRule(lotteryEntity.getLotteryRule());
        vo.setLotteryType(lotteryEntity.getLotteryType());
        vo.setLotteryJoinMark(lotteryEntity.getLotteryJoinMark());
        vo.setAwardSnapshoot(lotteryEntity.getAwardSnapshoot());
        vo.setIsFinished(new Date().after(lotteryEntity.getFinishTime()) ? 1 : 0);
        if (vo.getIsFinished() == 1) {
            vo.setRemainTime(0);
        } else {
            long remainTime = DateUtil.between(new Date(), lotteryEntity.getFinishTime(), DateUnit.SECOND, true);
            vo.setRemainTime((int) remainTime);
        }
        VssToken token = VssTokenThreadLocal.getToken();
        Integer thirdPartyUserId = token.getThirdPartyUserId();
        if (lotteryEntity.getLotteryRule() == 1) {
            // 随机抽奖
            vo.setIsJoin(1);
        } else {
            // 满足条件抽奖
            if (lotteryEntity.getLotteryType() == 2) {
                RoomsEntityDTO roomInfo = roomInnerService.getRoomInfo(reqVo.getRoomId());
                // 栏目订阅
                if (liveColumnService.isSubscribe(roomInfo.getColumnId(), thirdPartyUserId)) {
                    vo.setIsJoin(1);
                }
            } else if (lotteryEntity.getLotteryType() == 1) {
                // 房间点赞
                RoomsEntityDTO roomInfo = roomInnerService.getRoomInfo(reqVo.getRoomId());
                String key = RedisKey.ROOM_LIKE_ACCOUNT + roomInfo.getRoomId();
                if (redisTemplate.opsForSet().isMember(key, thirdPartyUserId)) {
                    vo.setIsJoin(1);
                } else {
                    String roomId = reqVo.getRoomId();
                    LambdaQueryWrapper<RoomLikesEntity> queryWrapper = Wrappers.lambdaQuery();
                    queryWrapper.eq(RoomLikesEntity::getRoomId, roomId);
                    queryWrapper.eq(RoomLikesEntity::getAccountId, thirdPartyUserId);
                    Integer count = roomLikeMapper.selectCount(queryWrapper);
                    if (count > 0) {
                        vo.setIsJoin(1);
                    }
                }
            } else if (lotteryEntity.getLotteryType() == 3) {
                // 指定评论
                String commentJoinKey = RedisKey.KEY_LOTTERY_COMMENT_JOIN + reqVo.getLotteryId();
                if (Boolean.TRUE.equals(redisTemplate.hasKey(commentJoinKey))) {
                    Boolean member = stringRedisTemplate.opsForSet().isMember(commentJoinKey, String.valueOf(thirdPartyUserId));
                    vo.setIsJoin(Boolean.TRUE.equals(member) ? 1 : 0);
                }

            }
        }
        return vo;
    }

    @Override
    public LotteryWinningInfo winningInfo(V4LotteryRecordReqVO reqVo) {
        VssToken token = VssTokenThreadLocal.getToken();
        RoomsEntityDTO roomInfo = roomInnerService.getRoomInfo(reqVo.getRoomId());
        if (roomInfo == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        LambdaQueryWrapper<LotteryRecordEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(LotteryRecordEntity::getSourceId, roomInfo.getRoomId());
        queryWrapper.eq(LotteryRecordEntity::getLotteryUserId, token.getThirdPartyUserId());
        List<LotteryRecordEntity> lotteryRecordEntityList = lotteryRecordRepository.getBaseMapper().selectList(queryWrapper);
        if (CollUtil.isNotEmpty(lotteryRecordEntityList)) {
            LotteryRecordEntity lotteryRecordEntity = lotteryRecordEntityList.get(0);
            LotteryWinningInfo info = new LotteryWinningInfo();
            info.setLotteryId(lotteryRecordEntity.getLotteryId());
            info.setRecordId(lotteryRecordEntity.getId());
            info.setLotteryUserRemark(lotteryRecordEntity.getLotteryUserRemark());
            info.setLotteryUserPhone(lotteryRecordEntity.getLotteryUserPhone());
            info.setRoomId(roomInfo.getRoomId());
            info.setLotteryUserName(lotteryRecordEntity.getLotteryUserName());
            LotteryEntity lotteryEntity = lotteryMapper.selectById(lotteryRecordEntity.getLotteryId());
            info.setTitle(lotteryEntity.getTitle());
            info.setLotteryTime(lotteryEntity.getBeginTime());
            info.setAwardSnapshoot(lotteryEntity.getAwardSnapshoot());
            return info;
        }
        return null;
    }

    @Override
    public LotteryRspVO end(V4LotteryEndReqVO req) {

        LotteryEntity lottery = lotteryMapper.selectById(req.getLotteryId());
        if (lottery == null) {
            throw new BusinessException(BizErrorCode.COMP_LOTTERY_NOT_FOUND);
        }
        if (Consts.LOTTERY_STATUS_END == lottery.getLotteryStatus()) {
            throw new BusinessException(BizErrorCode.COMP_LOTTERY_HAS_ENDED);
        }
        String roomId = req.getRoomId();
        RoomsEntityDTO roomsEntityDTO = roomInnerService.getRoomInfo(roomId);
        if (roomsEntityDTO == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        if (!StringUtils.equalsAnyIgnoreCase(lottery.getSourceId(), req.getRoomId())) {
            throw new BusinessException(BizErrorCode.COMP_LOTTERY_END_PARAM_ERROR);
        }
        lottery.setLotteryStatus(Consts.LOTTERY_STATUS_END);
        lottery.setUpdatedAt(LocalDateTime.now());
        lotteryMapper.updateById(lottery);
        //组装响应类
        List<LotteryRecordEntity> userRspVos = lotteryRecordMapper.selectList(Wrappers.<LotteryRecordEntity>lambdaQuery().eq(LotteryRecordEntity::getLotteryId, lottery.getId()));

        List<LotteryRecordEndVO> lrevos = new ArrayList<>();
        for (LotteryRecordEntity lotteryRecordEntity : userRspVos) {
            //判断是否是是自定义列表的规则
            LotteryRecordEndVO lotteryRecordVO;
            if (lottery.getLotteryType() == 11) {
                //自定义列表的用户需要去房间中进行匹配相关的用户,
                lotteryRecordVO = lotteryUserMapper.getByRoomAndLotteryUserId(Integer.parseInt(lotteryRecordEntity.getLotteryUserId()), lottery.getSourceId());
                log.info("查询是否存在此用户参数,{},{}", lotteryRecordEntity.getLotteryUserId(), lottery.getSourceId());
                if (lotteryRecordVO == null) {
                    lotteryRecordVO = new LotteryRecordEndVO();
                    BeanUtils.copyProperties(lotteryRecordEntity, lotteryRecordVO);
                    lotteryRecordVO.setLotteryUserId("0" + lotteryRecordEntity.getLotteryUserId());
                }
            } else {
                lotteryRecordVO = new LotteryRecordEndVO();
                BeanUtils.copyProperties(lotteryRecordEntity, lotteryRecordVO);
            }
            lrevos.add(lotteryRecordVO);
        }
        String key = RedisKey.KEY_LOTTERY_RULE_TEXT + roomId;
        String ruleText = stringRedisTemplate.opsForValue().get(key);

        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> content = new HashMap<>(4);
        content.put("lottery_rule_text", ruleText);
        content.put("extension", lottery.getExtension());
        content.put("lottery_winners", lrevos);
        String contentPath;
        try {
            contentPath = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(content);
        } catch (JsonProcessingException e) {
            log.error("结束抽奖失败", e);
            throw new BusinessException(BizErrorCode.COMP_LOTTERY_END_FAILURE);
        }
        String fileName = req.getLotteryId() + ".json";
        String path = ossService.upload(IOUtils.toInputStream(contentPath, StandardCharsets.UTF_8), fileName, "application/json");
        if (path == null) {
            throw new BusinessException("文件上传失败");
        }
        stringRedisTemplate.opsForValue().set(Consts.LOTTERY_WINNERS_JSON_URL + req.getLotteryId(), path, 86400, TimeUnit.SECONDS);
        RoomsEntityDTO room = roomInnerService.getRoomInfo(roomId);
        net.sf.json.JSONObject sendJson = new net.sf.json.JSONObject();
        sendJson.put("type", "lottery_end_guoxin");
        sendJson.put("room_id", roomId);
        sendJson.put("lottery_id", req.getLotteryId());
        paasService.sendMessage(room.getChannelId(), sendJson.toString());
        HashMap<String, Object> tollRecord = new HashMap<>(4);
        tollRecord.put("lottery_status", 1);
        tollRecord.put("lottery_id", req.getLotteryId());
        redisTemplate.opsForHash().putAll(RedisKey.INTERACT_TOOL_RECORDS + room.getRoomId(), tollRecord);

        LotteryRspVO lotteryRspVO = new LotteryRspVO();
        BeanUtils.copyProperties(lottery, lotteryRspVO);
        lotteryRspVO.setLotteryUsers(lrevos);
        stringRedisTemplate.expire(RedisKey.LOTTERY_ADD_LOCK + req.getRoomId(), 0L, TimeUnit.SECONDS);
        return lotteryRspVO;
    }

    @Override
    public LotteryAwardRspVO award(LotteryAwardReqVO req) {
        VssToken vssToken = VssTokenThreadLocal.getToken();
        Integer thirdPartyUserId = vssToken.getThirdPartyUserId();
        Validate.notNull(req);
        LotteryAwardRspVO lotteryAwardRspVO = new LotteryAwardRspVO();
        LotteryEntity lotteryEntity = lotteryMapper.selectById(req.getLotteryId());
        if (lotteryEntity == null) {
            throw new BusinessException(BizErrorCode.COMP_LOTTERY_NOT_FOUND);
        }
        LotteryRecordEntity lotteryRecordEntity = getLotteryRecordInfo(thirdPartyUserId, lotteryEntity);
        lotteryRecordEntity.setLotteryUserName(req.getLotteryUserName());
        lotteryRecordEntity.setLotteryUserPhone(req.getLotteryUserPhone());
        if ("[]".equals(req.getLotteryUserRemark()) || "{}".equals(req.getLotteryUserRemark()) || StringUtils.isBlank(req.getLotteryUserRemark())) {
            req.setLotteryUserRemark("");
        }
        lotteryRecordEntity.setLotteryUserRemark(req.getLotteryUserRemark());
        lotteryRecordEntity.setUpdatedAt(LocalDateTime.now());
        lotteryRecordMapper.updateById(lotteryRecordEntity);
        BeanUtils.copyProperties(lotteryRecordEntity, lotteryAwardRspVO, "preset");
        return lotteryAwardRspVO;
    }

    /**
     * 获取中奖记录信息
     *
     * @param thirdPartyUserId 用户id
     * @param lotteryEntity    抽奖信息
     * @return 中奖记录
     */
    private LotteryRecordEntity getLotteryRecordInfo(Integer thirdPartyUserId, LotteryEntity lotteryEntity) {
        LotteryRecordEntity lotteryRecordEntity;
//        自定义抽奖-使用当前用户的手机号去匹配中奖账户
        if (lotteryEntity.getLotteryType() == 11) {
            List<AccountVO> list = accountService.listByIds(thirdPartyUserId.toString());
            if (list.isEmpty()) {
                throw new BusinessException(BizErrorCode.EMPTY_ACCOUNT);
            }
            AccountVO accountVO = list.get(0);
            String phone = Optional.ofNullable(accountVO.getPhone()).orElse(0L).toString();
            lotteryRecordEntity = lotteryRecordMapper.selectOne(Wrappers.<LotteryRecordEntity>lambdaQuery()
                    .eq(LotteryRecordEntity::getLotteryId, lotteryEntity.getId())
                    .eq(LotteryRecordEntity::getLotteryUserPhone, phone));
        } else {
            lotteryRecordEntity = lotteryRecordMapper.selectOne(Wrappers.<LotteryRecordEntity>lambdaQuery()
                    .eq(LotteryRecordEntity::getLotteryId, lotteryEntity.getId())
                    .eq(LotteryRecordEntity::getLotteryUserId, thirdPartyUserId));
        }
        if (Objects.isNull(lotteryRecordEntity)) {
            throw new BusinessException(BizErrorCode.COMP_LOTTERY_USER_NOT_FOUND);
        }
        return lotteryRecordEntity;
    }


    @Override
    public WatchLotteryUsersGetRspVO usersGet(V4LotteryUsersGetReqVO reqVo) {


        LambdaQueryWrapper<LotteryRecordEntity> queryWrapper = Wrappers.<LotteryRecordEntity>lambdaQuery()
                .eq(StringUtils.isNotBlank(reqVo.getRoomId()), LotteryRecordEntity::getSourceId, reqVo.getRoomId())
                .eq(reqVo.getLotteryId() != null, LotteryRecordEntity::getLotteryId, reqVo.getLotteryId())
                .eq(StringUtils.isNotBlank(reqVo.getLotteryUserId()), LotteryRecordEntity::getLotteryUserId, reqVo.getLotteryUserId())
                .orderByDesc(LotteryRecordEntity::getId);
        // 获取count
        queryWrapper.last("limit 1");
        List<LotteryUserVO> collect = lotteryRecordMapper.selectList(queryWrapper).parallelStream().map(lotteryUser -> {
            LotteryUserVO lotteryUserVO = new LotteryUserVO();
            BeanUtils.copyProperties(lotteryUser, lotteryUserVO);
            return lotteryUserVO;
        }).collect(Collectors.toList());
        WatchLotteryUsersGetRspVO rspVo = new WatchLotteryUsersGetRspVO();
        BeanUtils.copyProperties(reqVo, rspVo);
        rspVo.setList(collect);

        return rspVo;
    }

    @Override
    public CheckAwardInfoRspVO checkAwardInfo(CheckAwardInfoReqVO reqVo) {

        VssToken vssToken = VssTokenThreadLocal.getToken();
        Integer thirdPartyUserId = vssToken.getThirdPartyUserId();


        LotteryEntity lotteryEntity = lotteryMapper.selectById(reqVo.getLotteryId());
        if (lotteryEntity == null) {
            throw new BusinessException(BizErrorCode.COMP_LOTTERY_NOT_FOUND);
        }
        getLotteryRecordInfo(thirdPartyUserId, lotteryEntity);
        // TODO setAwardInfo  判断中奖用户是否填写过 信息
        return CheckAwardInfoRspVO.builder().setAwardInfo(1).build();
    }

}
